﻿var Handler = {};
if (document.addEventListener) {//如果支持DOM标准
    Handler.add = function (element, eventType, handler) {
        element.addEventListener(eventType, handler, false);
    };
    Handler.remove = function (element, eventType, handler) {
        element.removeEventListener(eventType, handler, false);
    }
}
else if (document.attachEvent) {//IE事件模型

    Handler.add = function (element, eventType, handler) {

        //如果发现事件已经被注册的话，就直接推出函数
        if (Handler._find(element, eventType, handler) != -1) return;

        //传递一个模拟的事件对象,此处进行了定义
        var wrapedHandler = function (e) {
            if (!e) e = window.event;
            var event = {
                _event: e,
                type: e.type,//返回发生的事件类型（名称）。不戴on前缀的,onclick事件，返回的type值为click
                target: e.srcElement,//返回发生事件的DOM对象
                currentTarget: element,//可能和target值一样，也可能不一样。在事件处理函数中，应该使用这个属性，而不是this关键字
                relatedTarget: e.fromElement ? e.fromElement : e.toElement,//mouseover和mouseout两个事件中才会出现的事件属性
                eventPhase: (e.srcElement == element) ? 2 : 3,//表示事件传播的过程段。

                clientX: e.clientX, clientY: e.clientY,
                screenX: e.screenX, screenY: e.screenY,

                altKey: e.altKey, ctrlKey: e.ctrlKey,
                shiftKey: e.shiftKey, charCode: e.keyCode,

                stopPropagation: function () { this._event.cancelBubble = true; },
                preventDefault: function () { this._event.returnValue = false; }
            }

            if (Function.prototype.call) {
                handler.call(element, event);
            }
            else {
                element._currentHandler = handler;
                element._currentHandler(event);
                element._currentHandler = null;
            }
        }

        //绑定事件
        element.attachEvent("on" + eventType, wrapedHandler);


        var h = {
            element: element,//DOM
            eventType: eventType,//事件类型
            handler: handler,//fn，方法函数
            wrappedHandler: wrapedHandler//处理过的函数(兼容DOM标准对象的函数);
        }

        var d = element.document || element;
        var w = d.parentWindow;

        var id = Handler._uid(); //事件注册的唯一ID,每次都不一样,这里是调用_uid()这个function方法的
        if (!w._allHandlers) w._allHandlers = {}; //用来存储所有的事件注册的对象
        w._allHandlers[id] = h;//根据ID值来存放上面刚注册的事件

        if (!element._handlers) element._handlers = []; //当前元素上的事件数组（存放各种事件的数组）
        element._handlers.push(id);//使用上面的同一个ID来表示定义在element上面的事件。这里存放的事件在上面_allHandlers中使用同样的id存放的事件是一样的


        if (!w._onunloadHandlerRegistered) {//如果是第一次调用add方法， 卸载掉所有的事件
            w._onunloadHandlerRegistered = true; //下次就不再进入这个函数了
            w.attachEvent("onunload", Handler._removeAllHandlers);
        }

    }

    Handler.remove = function (element, eventType, handler) {
        var i = Handler._find(element, eventType, handler);
        if (i == -1) return;
        var d = element.document || element;
        var w = d.parentWindow;

        var handlerId = element._handlers[i];
        var h = w._allHandlers[handlerId];

        element.detachEvent("on" + eventType, h.wrappedHandler);

        element._handlers.splice(i, 1);

        delete w._allHandlers[handlerId];
    }

    Handler._find = function (element, eventType, handler) {

        var handlers = element._handlers;
        if (!handlers) return -1;

        var d = element.document || element;
        var w = d.parentWindow;

        for (var i = handlers.length - 1; i >= 0; i--) {
            var handlerId = handlers[i];
            var h = w._allHandlers[handlerId];
            if (h.eventType == eventType && h.handler == handler) return i;
        }
        return -1;
    }

    Handler._removeAllHandlers = function () {//在事件注册之前，移除所有的事件注册函数 
        var w = this;
        for (id in w._allHandlers) {

            var h = w._allHandlers[id];

            h.element.detachEvent("on" + h.eventType, h.wrappedHandler);

            delete w._allHandlers[id];
        }
    }

    Handler._counter = 0;
    Handler._uid = function () { return "h" + Handler._counter++; }
}
//如上的代码的思路我是如下理解的。
//1、符合W3C的DOM标准的浏览器使用addEventListener和removeEventListener进行事件的注册和删除(capture设置为false，在冒泡过程中触发)
//2、IE事件模型的浏览器中，事件对象和DOM标准的不一样。首先通过一个方法wrappedHandler用来兼容IE模型的浏览器可以使用DOM标准的事件对象的属性
//3、然后使用attachEvent方法进行注册事件,detachEvent进行事件的注销
//4、在ie模型中，使用一个对象，然后使用下标把注册的事件存储起来。绑定事件的那个DOM元素上面新建个数组对象，使用和上面一样的下标存储和这个dom元素相关的，不同类型的事件。




//鼠标事件  clientX获取鼠标相对文档的X轴坐标（不算滚动条）clientY获取Y轴坐标（不算滚动条）

var ToolTip = function () { };
ToolTip.x_offset = 25;
ToolTip.y_offset = 15;
ToolTip.delay = 500;

ToolTip.prototype.schedule = function (target, e) {
    var text = target.getAttribute("tooltip");
    if (!text) return; //如果没有内容就跳出函数

    var x = e.clientX + Geometry.getHorizontalScroll();
    var y = e.clientY + Geometry.getVerticalScroll();

    x += ToolTip.x_offset;
    y += ToolTip.y_offset;

    var self = this;
    var timer = window.setTimeout(function () { self.show(text, x, y); }, ToolTip.delay);

    Handler.add(target, "mouseout", mouseout);

    function mouseout() {
        self.hide();
        window.clearTimeout(timer);
        Handler.remove(target, "mouseout", mouseout);
    }
}


//拖拽文档元素  setCaption

function drag(elementToDrag, event) {
    var event = event || window.event;

    var startX = event.clientX, startY = event.clientY;

    var origX = elementToDrag.offsetLeft, origY = elementToDrag.offsetTop;

    var deltaX = startX - origX, deltaY = startY - origY;

    if (document.addEventListener) {
        document.addEventListener("mousemove", moveHandler, true);
        document.addEventListener("mouseup", upHandler, true);
    }
    else if (document.attachEvent) {
        elementToDrag.setCapture();

        elementToDrag.attachEvent("onmousemove", moveHandler);
        elementToDrag.attachEvent("onmouseup", upHandler);
        elementToDrag.attachEvent("onlosecapture", upHandler);
    } else {
        var oldmovehandler = document.onmousemove;
        var olduphandler = document.onmouseup;
        document.onmousemove = moveHandler;
        document.onmouseup = upHandler;
    }

    if (event.stopPropagation) {
        event.stopPropagation();
    } else {
        event.cancelBubble = true;
    }

    if (event.preventDefault) {
        event.preventDefault();
    } else {
        event.returnValue = false;
    }



    function moveHandler(e) {
        if (!e) e = window.event;
        elementToDrag.style.left = (e.clientX - deltaX) + 'px';
        elementToDrag.style.top = (e.clientY - deltaY) + 'px';

        if (e.stopPropagation) e.stopPropagation();
        else e.cancelBubble = true;

    }

    function upHandler(e) {
        if (!e) e = window.event;

        if (document.removeEventListener) {
            document.removeEventListener("mouseup", upHandler, true);
            document.removeEventListener("mousemove", moveHandler, true);
        }
        else if (document.attachEvent) {
            elementToDrag.detachEvent("onlosecapture", upHandler);
            elementToDrag.detachEvent("onmouseup", upHandler);
            elementToDrag.detachEvent("onmousemove", moveHandler);
            elementToDrag.releaseCapture();
        } else {
            document.onmouseup = olduphandler;
            document.onmousemove = oldmovehandler;
        }

        if (e.stopPropagation) e.stopPropagation();
        else e.cancelBubble = true;

    }

}




var m = function (x) {
    if (x <= 1) return1;
    return x * arguments.callee(x - 1);
}

//把对象属性用作参数，不必记住参数的传递顺序


var patter = /^[a-zA-Z][0-9a-zA-Z_]{6,30}/;


function recursion(x) {
    if (x <= 1) return 1;
    return x * arguments.callee(x - 1) + '\n';
}

var obj = function (msg) {
    this.msg = msg;
}

obj.prototype = {
    shout: function () {

        alert(this.msg);
    },
    waitAndShout: function () {
        var that = this;
        setTimeout(function () { that.shout() }, 2000);
    }
}


Array.prototype.uniq = function () {
    var _this = this, flag = true, newarr = [];
    for (var i = 0, len = _this.length; i < len; i++) {
        for (var j = 0, mlen = newarr.length; j < mlen; j++) {
            newarr[j] === _this[i] && (flag = false);
        }
        flag && newarr.push(_this[i]);
    }
    return newarr;
}

Array.prototype.unig = function () {
    var i = 0, o = {}, e = [];
    while (i < this.length) {
        o[this[i++]] = '';
    }

    for (var i in o) e.push(i);
    return e;
}

var a = [1, 2, 3, 4, 5, 1, 2, 3, 2, 4, 5];
var b = a.unig();

console.log(b);
window.onload = function () {
    Handler.add(document.getElementById("div"), "mousemove", fn1);
    var box = document.getElementById("box");
}
function fn1(e) {
    var pos = { x: 0, y: 0 };
    pos.x = e.clientX;
    pos.y = e.clientY;
    box.innerHTML = "x:" + pos.x + ";y:" + pos.y;
}


//滚动
var gallery = function (opt) {
    this.config = extend(gallery.defaults, opt);
    if (this.config.elem.length || this.config.Nav.length) return;
    var $nav = this.config.Nav;
    this.init(this.config);
}

gallery.defaults = {
    scrollNum: 1,
    curNum: 0
}

gallery.prototype = {
    init: function (opt) {
        var navUl = opt.Nav.getElementsByTagName("ul")[0];
        var li_len = opt.Nav.getElementsByTagName("li").length;
        navUl.style.width = opt.m_width * li_len + 'px';
        this.bindEvent(opt);
    },
    bindEvent: function (opt) {
        var prev = getClass("prev", opt.Nav)[0];
        var next = getClass("next", opt.Nav)[0];
        var that = this;
        Handler.add(prev, "click", function () { that.prev() });
        Handler.add(next, "click", function () { that.next() });
    },
    next: function () {
        var opt = this.config;
        var prev = getClass("next", opt.Nav)[0];
        if (hasClass("end", prev)) return;
        var Elem_ul = opt.Nav.getElementsByTagName("ul")[0];
        var li_len = opt.Nav.getElementsByTagName("li").length;
        if (opt.curNum < li_len) {
            Elem_ul.style.left = -opt.m_width + 'px';
            opt.curNum++;
        }
    },

    prev: function () {
        var opt = this.config;
        var prev = getClass("prev", opt.Nav)[0];
        if (hasClass("end", prev)) return;
    },
    showImg: function () {

    },
    move: function () {

    }
}

function extend(des, src) {
    for (k in src) {
        des[k] = src[k];
    }
    return des;
}

function getClass(clsName, content) {
    var doc = content || document, result = [];
    if (doc.getElementsByClassName) {
        return doc.getElementsByClassName(clsName);
    }

    var elem = doc.getElementsByTagName("*");
    for (var i = 0, len = elem.length; i < len; i++) {
        if (hasClass(clsName, elem[i])) result.push(elem[i]);
    }
    return result;
}

function hasClass(cls, node) {
    var names = node.className.split(/\s/);
    for (var j = 0, len = names.length; j < len; j++) {
        if (names[j] == cls) return true;
    }
    return false;
}

function addClass(elem, className) {
    if (!hasClass(elem, className)) elem.className += " " + className;
    return elem;
}

window.onload = function () {
    var o = new gallery({
        elem: document.getElementById("gallery"),
        m_width: 148,
        Nav: document.getElementById("galleryNav")
    });
}




function addEvent(elem, etype, fn) {
    elem = elem || document;
    if (document.addEventListener) {
        elem.addEventListener(etype, fn, false);
    } else if (document.attachEvent) {
        elem.attachEvent("on" + etype, fn);
    } else {
        elem["on" + etype] = fn;
    }
}



var mcvent = {};
if (document.addEventListener) {
    mcvent.add = function (elem, etype, fn) {
        elem.addEventListener(etype, fn, false);
    };
    mcvent.remove = function (elem, etype, fn) {
        elem.removeEventListener(etype, fn, false);
    }
}else {   //首先移除dom所有的事件注册
    mcvent.add = function (elem, etype, fn) {
        if (-1 != mcvent._find(elem, etype, fn)) return;//如果elem对象上面找到了etype句柄注册的fn函数，就跳出函数。防止同一个dom对象上的同一事件句柄被注册多次。

        //模拟一个事件对象
        var fixie = function (e) {
            if (!e) e = window.event;

            var event = {}
            if (Function.prototype.call) {
                fn.call(elem, event);
            } else {
                elem.fns = fn;
                elem.fns(event);
                elem.fns = null;
            }
        }

        //绑定事件
        elem.attachEvent("on" + etype, fixie);

        //把绑定在elem对象上面的etype事件句柄的fn函数存储起来
        var h2 = {
            elem: elem,
            etype: etype,
            fn: fn,
            fixie: fixie
        }

        var d2 = elem.document || elem;
        var m2 = d2.parentWindow;

        var id = mcvent.guid;
        if (!m2.obj) m2.obj = {};
        m2.obj[id] = h2;
        if (!elem.fns) elem.fns = [];
        elem.fns.push(id);

        if (!m2._onunload) {
            mc._onunload = true;
            m2.attachEvent("onunload", mcvent._removeallfn);
        }
    },
    mcvent.remove = function (elem, etype, fn) {
        var i = mcvent._find(elem, etype, fn);
        if (-1 != i) return;

        var d2 = elem.document || elem;
        var m2 = d2.parentWindow;

        var fnid = elem.fns[i];
        var hs = m2.obj[i];
        elem.detachEvent("on" + etype, hs.fixie);
        elem.fns.splice(i, 1);
        delete m2.obj[fnid];
    },
    mcvent._find = function (elem, etype, fn) {
        var fns = elem.arrfns;
        if (!fns) return -1;

        var d2 = elem.document || elem;
        var w2 = d2.parentWindow;

        for (var i = 0, len = fns.length; i < len; i++) {
            var fnid = fns[i];
            var h = w2._allHandlers[i];
            if (h.etype == etype && h.fn == fn) return i;
        }

        return -1;

    },
    mcvent._removeallfn = function () {
        var w = this;
        for (var d in w.obj) {
            var h = w.obj[d];

            window.detachEvent("on" + h.etype, h.fixie);
            delete w.obj[d];
        }
    }

    mcvent.couent = 0;
    mcvent.guid = function () {
        return mcvent.couent++;
    }
}

